home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / BARNET / INTERNET / PGP / PGP263I / pgp263i / src / c / language < prev    next >
Encoding:
Text File  |  1997-05-23  |  11.8 KB  |  511 lines

  1. /*
  2.    language.c - Foreign language translation for PGP
  3.    Finds foreign language "subtitles" for English phrases
  4.    in external foriegn language text file.
  5.  
  6.    (c) Copyright 1990-1996 by Philip Zimmermann.  All rights reserved.
  7.    The author assumes no liability for damages resulting from the use
  8.    of this software, even if the damage results from defects in this
  9.    software.  No warranty is expressed or implied.
  10.  
  11.    Note that while most PGP source modules bear Philip Zimmermann's
  12.    copyright notice, many of them have been revised or entirely written
  13.    by contributors who frequently failed to put their names in their
  14.    code.  Code that has been incorporated into PGP from other authors
  15.    was either originally published in the public domain or is used with
  16.    permission from the various authors.
  17.  
  18.    PGP is available for free to the public under certain restrictions.
  19.    See the PGP User's Guide (included in the release package) for
  20.    important information about licensing, patent restrictions on
  21.    certain algorithms, trademarks, copyrights, and export controls.
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28. #include "usuals.h"
  29. #include "fileio.h"
  30. #include "language.h"
  31. #include "pgp.h"
  32. #include "charset.h"
  33. #include "armor.h"
  34.  
  35. /* gjm:
  36.  * We need to replace .txt with /txt etc. We also, alas, need
  37.  * to shorten these filenames, *unless* PGP$LongConfNames is
  38.  * set at startup time.
  39.  * The fact that this is variable at runtime means that these
  40.  * things are no longer constant strings.
  41.  */
  42. #ifdef RISC_OS
  43. static char gjm_subtitles_file[20]="lang/txt";
  44. static char gjm_lang_indexfile[20]="lang/idx";
  45. #define SUBTITLES_FILE gjm_subtitles_file
  46. #define LANG_INDEXFILE gjm_lang_indexfile
  47. #define gjm_SFlong "language/txt"
  48. #define gjm_LIlong "language/idx"
  49. #else
  50. #define SUBTITLES_FILE    "language.txt"
  51. #define LANG_INDEXFILE    "language.idx"
  52. #endif
  53.  
  54. #define    STRBUFSIZE        2048
  55.  
  56. char language[16] = "en";    /* The language code, defaults to English */
  57. static char *strbuf;
  58. static char lang[16];        /* readstr sets this to the language id of
  59.                    the msg it last read */
  60. static int subtitles_available = 0;
  61. static int line = 0;
  62. /*      subtitles_available is used to determine if we know whether the special
  63.    subtitles_file exists.  subtitles_available has the following values:
  64.    0  = first time thru, we don't yet know if subtitles_file exists.
  65.    1  = we have already determined that subtitles_file exists.
  66.    -1 = we have already determined that subtitles_file does not exist.
  67.  */
  68.  
  69. #define    NEWLINE        0
  70. #define    COMMENT        1
  71. #define    INSTRING    2
  72. #define    ESCAPE        3
  73. #define    IDENT        4
  74. #define    DONE        5
  75. #define    ERROR        6
  76. #define    ERR1        7
  77.  
  78. /* Look for and return a quoted string from the file.
  79.  * If nlabort is true, return failure if we find a blank line
  80.  * before we find the opening quote.
  81.  */
  82. static char *
  83.  readstr(FILE * f, char *buf, int nlabort)
  84. {
  85.     int c, d;
  86.     char *p = buf;
  87.     int state = NEWLINE;
  88.     int i = 0;
  89.  
  90.     while ((c = getc(f)) != EOF) {
  91.     if (c == '\r')
  92.         continue;
  93.     /* line numbers are only incremented when creating index file */
  94.     if (line && c == '\n')
  95.         ++line;
  96.     switch (state) {
  97.     case NEWLINE:
  98.         switch (c) {
  99.         case '#':
  100.         state = COMMENT;
  101.         break;
  102.         case '"':
  103.         state = INSTRING;
  104.         break;
  105.         case '\n':
  106.         if (nlabort) {
  107.             *buf = '\0';
  108.             return buf;
  109.         }
  110.         default:
  111.         if (i == 0 && isalnum(c)) {
  112.             state = IDENT;
  113.             lang[i++] = c;
  114.             break;
  115.         }
  116.         if (!isspace(c)) {
  117.             fprintf(stderr, "language.txt:%d: syntax error\n", line);
  118.             state = ERROR;
  119.         }
  120.         }
  121.         break;
  122.     case COMMENT:
  123.         if (c == '\n')
  124.         state = NEWLINE;
  125.         break;
  126.     case INSTRING:
  127.         switch (c) {
  128.         case '\\':
  129.         state = ESCAPE;
  130.         break;
  131.         case '"':
  132.         state = DONE;
  133.         break;
  134.         default:
  135.         *p++ = c;
  136.         }
  137.         break;
  138.     case ESCAPE:
  139.         switch (c) {
  140.         case 'n':
  141.         *p++ = '\n';
  142.         break;
  143.         case 'r':
  144.         *p++ = '\r';
  145.         break;
  146.         case 't':
  147.         *p++ = '\t';
  148.         break;
  149.         case 'e':
  150. #ifdef EBCDIC
  151.         *p++ = ESC;
  152. #else
  153.         *p++ = '\033';
  154. #endif
  155.         break;
  156.         case 'a':
  157. #ifdef EBCDIC
  158.         *p++ = '\a';
  159. #else
  160.         *p++ = '\007';
  161. #endif
  162.         break;
  163.         case '#':
  164.         case '"':
  165.         case '\\':
  166.         *p++ = c;
  167.         break;
  168.         case '\n':
  169.         break;
  170.         case '0':
  171.         case '1':
  172.         case '2':
  173.         case '3':
  174.         case '4':
  175.         case '5':
  176.         case '6':
  177.         case '7':
  178.         d = c - '0';
  179.         while ((c = fgetc(f)) >= '0' && c <= '7')
  180.             d = 8 * d + c - '0';
  181. #ifdef EBCDIC
  182. /* dirty hack for \007 chars in LANG:    LANG("\n\007....")
  183.    The right way is to replace all \007 by \a in the args of LANG() */
  184.         if (d == 7) d = '\a';
  185. #endif
  186.         *p++ = d;
  187.         ungetc(c, f);
  188.         break;
  189.         default:
  190.         fprintf(stderr,
  191.             "language.txt:%d: illegal escape sequence: '\\%c'\n",
  192.             line, c);
  193.         break;
  194.         }
  195.         state = INSTRING;
  196.         break;
  197.     case IDENT:        /* language identifier */
  198.         if (c == ':') {
  199.         state = NEWLINE;
  200.         break;
  201.         }
  202.         if (c == '\n' && strncmp(lang, "No translation", 14) == 0) {
  203.         i = 0;
  204.         state = NEWLINE;
  205.         break;
  206.         }
  207.         lang[i++] = c;
  208.         if (i == 15 || !isalnum(c) && !isspace(c)) {
  209.         lang[i] = '\0';
  210.         fprintf(stderr,
  211.             "language.txt:%d: bad language identifier: '%s'\n",
  212.             line, lang);
  213.         state = ERROR;
  214.         i = 0;
  215.         }
  216.         break;
  217.     case DONE:
  218.         if (c == '\n') {
  219.         lang[i] = '\0';
  220.         *p = '\0';
  221.         return buf;
  222.         }
  223.         if (!isspace(c)) {
  224.         fprintf(stderr,
  225.             "language.txt:%d: extra characters after '\"'\n",
  226.             line);
  227.         state = ERROR;
  228.         }
  229.         break;
  230.     case ERROR:
  231.         if (c == '\n')
  232.         state = ERR1;
  233.         break;
  234.     case ERR1:
  235.         state = (c == '\n' ? NEWLINE : ERROR);
  236.         break;
  237.     }
  238.     }
  239.     if (state != NEWLINE)
  240.     fprintf(stderr, "language.txt: unexpected EOF\n");
  241.     return NULL;
  242. }
  243.  
  244. #ifdef TEST
  245. main()
  246. {
  247.     char buf[2048];
  248.  
  249.     line = 1;
  250.     while (readstr(stdin, buf, 0)) {
  251.     printf("\nen: <%s>\n", buf);
  252.     while (readstr(stdin, buf, 1) && *buf != '\0')
  253.         printf("%s: <%s>\n", lang, buf);
  254.     }
  255.     exit(0);
  256. }
  257. #else
  258.  
  259. static struct indx_ent {
  260.     word32 crc;
  261.     long offset;
  262. } *indx_tbl = NULL;
  263.  
  264. static int max_msgs = 0;
  265. static long nmsg = 0;
  266.  
  267. static FILE *langf;
  268.  
  269. static void init_lang(void);
  270.  
  271. static int make_indexfile(char *);
  272.  
  273. /*
  274.  * uses 24-bit CRC function from armor.c
  275.  */
  276. static word32
  277.  message_crc(char *s)
  278. {
  279.     return crcbytes((byte *) s, strlen(s), (word32) 0);
  280. }
  281.  
  282. /*
  283.  * lookup file offset in indx_tbl
  284.  */
  285. static long lookup_offset(word32 crc)
  286. {
  287.     int i;
  288.  
  289.     for (i = 0; i < nmsg; ++i)
  290.     if (indx_tbl[i].crc == crc)
  291.         return indx_tbl[i].offset;
  292.     return -1;
  293. }
  294.  
  295.  
  296. /*
  297.  * return foreign translation of s
  298.  */
  299. char *
  300.  LANG(char *s)
  301. {
  302.     long filepos;
  303. #ifdef MACTC5
  304.     extern Boolean contains_yesNo, contains_enough, contains_badpass;
  305.     contains_yesNo = (((void *) strstr(s, "(Y/n)?") != NULL) ||
  306.         ((void *) strstr(s, "(y/N)?") != NULL));
  307.     contains_enough = ((void *) strstr(s, "Enough") != NULL);
  308.     contains_badpass = (strstr(s, "Bad pass phrase.") != NULL);
  309. #endif /* MACTC5 */
  310.     if (subtitles_available == 0)
  311.     init_lang();
  312.     if (subtitles_available < 0)
  313.     return s;
  314.  
  315.     filepos = lookup_offset(message_crc(s));
  316.     if (filepos == -1) {
  317.     return s;
  318.     } else {
  319.     fseek(langf, filepos, SEEK_SET);
  320.     readstr(langf, strbuf, 1);
  321.     }
  322.  
  323.     if (strbuf[0] == '\0')
  324.     return s;
  325.  
  326. #ifndef EBCDIC /* no conversion for ebcdic printf() messages needed */
  327.     for (s = strbuf; *s; ++s)
  328.     *s = EXT_C(*s);
  329. #endif
  330.     return strbuf;
  331. }
  332.  
  333.  
  334. static struct {
  335.     long lang_fsize;        /* size of language.txt */
  336.     char lang[16];        /* language identifier */
  337.     long nmsg;            /* number of messages */
  338. } indx_hdr;
  339.  
  340.  
  341. /*
  342.  * initialize the index table: read it from language.idx or create
  343.  * a new one and write it to the index file. A new index file is
  344.  * created if the language set in config.pgp doesn't match the one
  345.  * in language.idx or if the size of language.txt has changed.
  346.  */
  347. static void init_lang()
  348. {
  349.     char indexfile[MAX_PATH];
  350.     char subtitles_file[MAX_PATH];
  351.     FILE *indexf;
  352. #ifdef PGP_SYSTEM_DIR
  353.     int use_system_wide_lang = 0;
  354. #endif
  355.  
  356. /* gjm:
  357.  * We need to set up the filenames before anything else
  358.  * can be used.
  359.  */
  360. #ifdef RISC_OS
  361.     if (getenv("PGP$LongConfNames") != NULL) {
  362.     strcpy(gjm_subtitles_file,gjm_SFlong);
  363.     strcpy(gjm_lang_indexfile,gjm_LIlong);
  364.     }
  365. #endif
  366.     if (strcmp(language, "en") == 0) {
  367.     subtitles_available = -1;
  368.     return;            /* use default messages */
  369.     }
  370.     buildfilename(subtitles_file, SUBTITLES_FILE);
  371.     langf = fopen(subtitles_file, FOPRBIN); /* Open file in binary mode... */
  372.     if (langf == NULL) {
  373. #ifdef PGP_SYSTEM_DIR
  374.     strcpy(subtitles_file, PGP_SYSTEM_DIR);
  375.     strcat(subtitles_file, SUBTITLES_FILE);
  376.     langf = fopen(subtitles_file, FOPRBIN); /* Open file in binary mode... */
  377.     use_system_wide_lang = 1;
  378.     if (langf == NULL)
  379. #endif
  380.     {
  381.         subtitles_available = -1;
  382.         return;
  383.     }
  384.     }
  385.     init_crc();
  386.     strbuf = (char *) malloc(STRBUFSIZE);
  387.     if (strbuf == NULL) {
  388.     fprintf(stderr, "Not enough memory for foreign subtitles\n");
  389.     fclose(langf);
  390.     subtitles_available = -1;
  391.     return;
  392.     }
  393. #ifdef PGP_SYSTEM_DIR
  394.     if (use_system_wide_lang) {
  395.     strcpy(indexfile, PGP_SYSTEM_DIR);
  396.     strcat(indexfile, LANG_INDEXFILE);
  397.     } else
  398. #endif
  399.     buildfilename(indexfile, LANG_INDEXFILE);
  400.     indexf = fopen(indexfile, FOPRBIN);
  401.     if (indexf != NULL) {
  402.     if (fread(&indx_hdr, 1, sizeof(indx_hdr),
  403.           indexf) == sizeof(indx_hdr) &&
  404.         indx_hdr.lang_fsize == fsize(langf) &&
  405.         strcmp(indx_hdr.lang, language) == 0) {
  406.         nmsg = indx_hdr.nmsg;
  407.         indx_tbl = (struct indx_ent *) malloc(nmsg *
  408.                           sizeof(struct indx_ent));
  409.         if (indx_tbl == NULL) {
  410.         fprintf(stderr, "Not enough memory for foreign subtitles\n");
  411.         fclose(indexf);
  412.         fclose(langf);
  413.         subtitles_available = -1;
  414.         return;
  415.         }
  416.         if (fread(indx_tbl,
  417.               sizeof(struct indx_ent), nmsg, indexf) != nmsg) {
  418.         free(indx_tbl);    /* create a new one */
  419.         indx_tbl = NULL;
  420.         }
  421.     }
  422.     fclose(indexf);
  423.     }
  424.     if (indx_tbl == NULL && make_indexfile(indexfile) < 0) {
  425.     fclose(langf);
  426.     subtitles_available = -1;
  427.     } else {
  428.     subtitles_available = 1;
  429.     }
  430. }
  431.  
  432.  
  433. static int make_indexfile(char *indexfile)
  434. {
  435.     FILE *indexf;
  436.     long filepos;
  437.     int total_msgs = 0;
  438.     char *res;
  439.  
  440.     if (verbose)        /* must be set in config.pgp */
  441.     fprintf(stderr,
  442.         "Creating language index file '%s' for language \"%s\"\n",
  443.         indexfile, language);
  444.     rewind(langf);
  445.     indx_hdr.lang_fsize = fsize(langf);
  446.     strncpy(indx_hdr.lang, language, 15);
  447.     init_crc();
  448.     line = 1;
  449.     nmsg = 0;
  450.     while (readstr(langf, strbuf, 0)) {
  451.     if (nmsg == max_msgs) {
  452.         if (max_msgs) {
  453.         max_msgs *= 2;
  454.         indx_tbl = (struct indx_ent *) realloc(indx_tbl, max_msgs *
  455.                         sizeof(struct indx_ent));
  456.         } else {
  457.         max_msgs = 400;
  458.         indx_tbl = (struct indx_ent *) malloc(max_msgs *
  459.                         sizeof(struct indx_ent));
  460.         }
  461.         if (indx_tbl == NULL) {
  462.         fprintf(stderr, "Not enough memory for foreign subtitles\n");
  463.         return -1;
  464.         }
  465.     }
  466.     ++total_msgs;
  467.     indx_tbl[nmsg].crc = message_crc(strbuf);
  468.     if (lookup_offset(indx_tbl[nmsg].crc) != -1)
  469.         fprintf(stderr,
  470.             "language.txt:%d: Message CRC not unique: \"%s\"\n",
  471.             line, strbuf);
  472.     do {
  473.         filepos = ftell(langf);
  474.         res = readstr(langf, strbuf, 1);    /* Abort if find newline
  475.                            first */
  476.     } while (res && strbuf[0] != '\0' && strcmp(language, lang) != 0);
  477.  
  478.     if (res == NULL)
  479.         break;
  480.     if (strbuf[0] == '\0')    /* No translation */
  481.         continue;
  482.  
  483.     indx_tbl[nmsg].offset = filepos;
  484.     ++nmsg;
  485.     do
  486.         res = readstr(langf, strbuf, 1);    /* Abort if find newline
  487.                            first */
  488.     while (res && strbuf[0] != '\0');
  489.     }
  490.     line = 0;
  491.     indx_hdr.nmsg = nmsg;
  492.     if (nmsg == 0) {
  493.     fprintf(stderr, "No translations available for language \"%s\"\n\n",
  494.         language);
  495.     return -1;
  496.     }
  497.     if (verbose || total_msgs != nmsg)
  498.     fprintf(stderr, "%d messages, %d translations\n\n", total_msgs, nmsg);
  499.  
  500.     if ((indexf = fopen(indexfile, FOPWBIN)) == NULL) {
  501.     fprintf(stderr, "Cannot create %s\n", indexfile);
  502.     } else {
  503.     fwrite(&indx_hdr, 1, sizeof(indx_hdr), indexf);
  504.     fwrite(indx_tbl, sizeof(struct indx_ent), nmsg, indexf);
  505.     if (ferror(indexf) || fclose(indexf))
  506.         fprintf(stderr, "error writing %s\n", indexfile);
  507.     }
  508.     return 0;
  509. }
  510. #endif                /* TEST */
  511.